#include "LoadCPMessage.hpp"

using namespace BFT::messages;

LoadCPMessage::LoadCPMessage(boost::shared_ptr<char> _token, int _token_size, uint32_t _seq, uint32_t _sender)
	: MacMessage::MacMessage(LOAD_CP_MESSAGE, computeSize(_token_size), _sender)
{
	seqNo = _seq;
	token = _token;
	token_size = (uint32_t)_token_size;
	
	int bytes_size;
	boost::shared_ptr<char> bytes = getBytes(bytes_size);
	
	int offset = getOffset();
	
//	fprintf(stderr,"loadcpmessage constructor.");
//	MacMessage::printInfo();
//	fprintf(stderr,"token.usecount %d, token size %d\n",_token.use_count(), _token_size);
	//write the sequence number
	*(uint32_t*)(bytes.get()+offset) = htonl(seqNo);
	offset += SEQUENCE_NUMBER_SIZE;
	
	//write the token size
	*(uint32_t*)(bytes.get()+offset) = htonl((uint32_t)token_size);
	offset += TOKEN_SIZE_SIZE;
	
	//write the token
	memcpy( (void*)(bytes.get()+offset), (const void*)(token.get()) , token_size);
	offset += token_size;
}

LoadCPMessage::LoadCPMessage(boost::shared_ptr<char> _bytes, int _bytes_size)
	: MacMessage::MacMessage(_bytes, _bytes_size)
{
	if (getTag() != LOAD_CP_MESSAGE)
	{
		fprintf(stderr, "trying to create a LoadCPMessage from invalid bytes. Expected tag: %d, actual tag:%d \n",
			LOAD_CP_MESSAGE,getTag());
		exit(102);
	}
	
	unsigned int offset = getOffset();
	
	//read the sequence number
	seqNo = ntohl(*(uint32_t*)(_bytes.get()+offset));
	offset += SEQUENCE_NUMBER_SIZE;
	
	//read the token size
	token_size = ntohl( *(uint32_t*)(_bytes.get()+offset));
	offset += TOKEN_SIZE_SIZE;
	
	token.reset( (char*)malloc(token_size), free);
	
	//read the token
	memcpy( (void*)(token.get()) , (const void*)(_bytes.get()+offset) , token_size);
	offset += token_size;
	
	if (offset != _bytes_size - getAuthenticationSize())
	{
		fprintf(stderr, "Trying to create a LoadCPMessage from invalid bytes\n");
		exit(103);
	}
}

bool LoadCPMessage::matches(boost::shared_ptr<BFT::messages::VerifiedMessageBase> _other_vmb)
{
	//TODO find a better way to downcast
	//boost::shared_ptr<LoadCPMessage> other_lcp = boost::static_pointer_cast<BFT::messages::LoadCPMessage> (_other_vmb);

	int lcp_size;
	boost::shared_ptr<char> lcp_bytes = _other_vmb.get()->getBytes(lcp_size);
	boost::shared_ptr<LoadCPMessage> other_lcp (new LoadCPMessage(lcp_bytes,lcp_size));

	bool match = seqNo == other_lcp.get()->getSequenceNumber() && token_size == (uint32_t)other_lcp.get()->getTokenSize(); 
	if (match)
	{
		boost::shared_ptr<char> other_token = other_lcp.get()->getToken();
		for (unsigned int i =0 ; i<token_size && match; i++)
		{
			match = token.get()[i] == other_token.get()[i];
		}
	}
	
	return match;
}

uint32_t LoadCPMessage::computeSize(int _token_size)
{
	return SEQUENCE_NUMBER_SIZE + TOKEN_SIZE_SIZE + _token_size;
}

void LoadCPMessage::printInfo()
{
	fprintf(stdout,"LoadCPMessage information...\n");
	fprintf(stdout,"seqNo: %d\ntoken size: %d\ntoken: ",seqNo, token_size);
	for (unsigned int i=0; i< token_size; i++)
		fprintf(stdout,"|%02X",(unsigned char)token.get()[i]);
	fprintf(stdout,"\n");
}
